﻿using System;
using System.Xml;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace iReaper.IndexBuilder.XmlSource
{
    public class RSSParser : IIndexParser
    {
        #region IIndexParser Members

        // Get channel video/audio information from: http://channel9.msdn.com/Feeds/RSS/
        // The rss of channel nine support standard "media" rss extension, 
        // hence it's much easier to parse and organize the content.

        public Channel Parse(TextReader txtReader)
        {
            XmlTextReader reader = new XmlTextReader(txtReader);

            if (reader.ReadToFollowing("channel"))
            {
                Channel channel;
                ParseChannel(reader.ReadSubtree(), out channel);
                return channel;
            }

            return null;
        }

        #endregion

        private void ParseChannel(XmlReader reader, out Channel channel)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            channel = new Channel();

            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    switch (reader.LocalName)
                    {
                        case "title":
                            channel.Title = reader.ReadString();
                            break;

                        case "image":
                            if (reader.ReadToFollowing("url"))
                            {
                                string url = reader.ReadString();
                                Uri uri;
                                if (Uri.TryCreate(url, UriKind.Absolute, out uri))
                                {
                                    channel.Image = uri;
                                }
                                else
                                {
                                    channel.Image = null;
                                }
                            }
                            break;

                        case "description":
                            channel.Description = reader.ReadString();
                            break;

                        case "link":
                            Uri lUri;
                            if (Uri.TryCreate(reader.ReadString(), UriKind.Absolute, out lUri))
                            {
                                channel.Link = lUri;
                            }
                            else
                            {
                                channel.Link = null;
                            }
                            break;

                        case "pubDate":
                            string element = reader.ReadString();
                            DateTime dt;
                            if (DateTime.TryParse(element, out dt))
                            {
                                channel.LastUpdateTime = dt;
                            }
                            else
                            {
                                channel.LastUpdateTime = DateTime.MinValue;
                            }
                            break;

                        case "item":
                            Channel.ContentItem item;
                            ParseContentItem(reader.ReadSubtree(), out item);
                            if (item != null)
                            {
                                channel.Items.Add(item);
                            }
                            break;

                    }
                }
            }
        }

        private void ParseContentItem(XmlReader reader, out iReaper.IndexBuilder.Channel.ContentItem item)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            Channel.ContentItem cItem = new Channel.ContentItem();
            while (reader.Read())
            {
                if (reader.IsStartElement())
                {
                    switch (reader.LocalName)
                    {
                        case "title":
                            cItem.Titile = reader.ReadString();
                            break;

                        case "description":
                            cItem.Description = reader.ReadString();
                            break;

                        case "group":
                            if (reader.NamespaceURI == Common.Media)
                            {
                                cItem.Medias = ParseMediaGroup(reader.ReadSubtree());
                            }
                            break;

                        case "pubDate":
                            string element = reader.ReadString();
                            DateTime dt;
                            if (DateTime.TryParse(element, out dt))
                            {
                                cItem.DateOfPublish = dt;
                            }
                            else
                            {
                                cItem.DateOfPublish = DateTime.MinValue;
                            }
                            break;

                        case "creator":
                            cItem.Author = reader.ReadString();
                            break;

                        case "link":
                            string url = reader.ReadString();
                            Uri uri;
                            if (Uri.TryCreate(url, UriKind.Absolute, out uri))
                            {
                                cItem.Url = uri;
                            }
                            break;

                    }
                }
            }

            item = cItem;
        }

        private Channel.Media[] ParseMediaGroup(XmlReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            List<Channel.Media> list = new List<Channel.Media>();

            while (reader.Read())
            {
                if (reader.IsStartElement("content", Common.Media))
                {
                    string url = reader.GetAttribute("url");
                    long fileSize = -1;
                    long.TryParse(reader.GetAttribute("fileSize"), out fileSize);
                    string contentType = reader.GetAttribute("type");

                    Channel.Media media = new Channel.Media();
                    media.Url = new Uri(url);
                    media.ContentType = contentType;
                    media.ContentLength = fileSize;

                    list.Add(media);
                }
            }

            return list.ToArray();
        }
    }
}
